﻿using AppSocketModel;
using BCGPSCommon;
using BCGPSMongoData;
using MongoDB.Driver;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;

namespace AppSocketService.Device
{
    public class DeviceService : IDeviceService
    {
        private readonly MongoDBCommand<DeviceDto> mongoDBCommand = new MongoDBCommand<DeviceDto>("Device");
        private readonly IRedisService redisService;

        public DeviceService(IRedisService redisService)
        {
            this.redisService = redisService;
        }

        #region 初始化Redis
        public List<DeviceDto> InitRedisGetAll()
        {
            return mongoDBCommand.SelectDocumentsAsync(s => s.IMEI != null).GetAwaiter().GetResult();

        }
        #endregion

        #region 设备注册
        public void Login(DeviceDto deviceDto)
        {
            DeviceDto dto;

            //此处不能读redis ,因为最新数据更新时间不写redis
            //dto = redisService.Get<DeviceDto>(GeneralContainer.RedisNameSpaceIMEIDevice + deviceDto.IMEI);            
            //if(dto == null)
            dto = mongoDBCommand.SelectDocumentAsync(s => s.IMEI == deviceDto.IMEI).GetAwaiter().GetResult();

            if (dto == null)
            {
                FristLogin(deviceDto);
            }
            else
            {
                if (dto.IsNeedReset)
                {
                    ResetLogin(deviceDto, dto);
                }
                else
                {
                    ReLogin(deviceDto, dto);
                }
            }
        }

        private void FristLogin(DeviceDto deviceDto)
        {
            deviceDto.FristLoginTime = BCGPSCommon.MongoDBDateTime.GetNowUtc();
            deviceDto.LastLoginTime = deviceDto.FristLoginTime;
            deviceDto.LastDataTime = deviceDto.FristLoginTime;
            deviceDto.LoginTimes = 1;
            deviceDto.GpsValidDataCount = 0;
            deviceDto.GpsInValidDataCount = 0;
            deviceDto.LbsValidDataCount = 0;
            deviceDto.LbsInValidDataCount = 0;
            deviceDto.ResetCountTimes = 0;
            deviceDto.OnLineTime = 0;
            deviceDto.OffLineTime = 0;

            mongoDBCommand.InsertDocumentAsync(deviceDto).GetAwaiter().GetResult();
            redisService.AddAsync(GeneralContainer.RedisNameSpaceIMEIDevice + deviceDto.IMEI, deviceDto);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="deviceDto">new</param>
        /// <param name="dto">old</param>
        private void ResetLogin(DeviceDto deviceDtoNew, DeviceDto dto)
        {
            Msg.WirteLine("AfterResetFristLogin", 150, '.');
            deviceDtoNew.IsNeedReset = false;
            deviceDtoNew.LoginTimes = 1;
            deviceDtoNew.OnLineTime = 0;
            deviceDtoNew.OffLineTime = 0;
            deviceDtoNew.OnLineTimeString = "0";
            deviceDtoNew.OffLineTimeString = "0";
            deviceDtoNew.FristLoginTime = BCGPSCommon.MongoDBDateTime.GetNowUtc();
            deviceDtoNew.LastLoginTime = deviceDtoNew.FristLoginTime;
            deviceDtoNew.LastDataTime = deviceDtoNew.FristLoginTime;
            deviceDtoNew.ModifyTime = deviceDtoNew.FristLoginTime;

            deviceDtoNew.GpsValidDataCount = 0;
            deviceDtoNew.GpsInValidDataCount = 0;
            deviceDtoNew.LbsValidDataCount = 0;
            deviceDtoNew.LbsInValidDataCount = 0;
            deviceDtoNew.ResetCountTime = dto.ResetCountTime;
            deviceDtoNew.ResetCountTimes = dto.ResetCountTimes;

            deviceDtoNew.FristResetTotal = deviceDtoNew.ResetTotal;
            deviceDtoNew.LastResetCount = 0;


            var update = Builders<DeviceDto>.Update
                .Set(s => s.HardwareVersion, deviceDtoNew.HardwareVersion)
                .Set(s => s.HardwareCode, deviceDtoNew.HardwareCode)
                .Set(s => s.FirmwareVersion, deviceDtoNew.FirmwareVersion)
                .Set(s => s.FirmwareCode, deviceDtoNew.FirmwareCode)
                .Set(s => s.deviceType, deviceDtoNew.deviceType)
                .Set(s => s.ResetCount, deviceDtoNew.ResetCount)
                .Set(s => s.ResetTotal, deviceDtoNew.ResetTotal)
                .Set(s => s.TimeSpan, deviceDtoNew.TimeSpan)
                .Set(s => s.SleepTime, deviceDtoNew.SleepTime)
                .Set(s => s.SleepTimeOnErr, deviceDtoNew.SleepTimeOnErr)
                .Set(s => s.SendTimes, deviceDtoNew.SendTimes)
                .Set(s=>s.BatteryVoltage,deviceDtoNew.BatteryVoltage)
                .Set(s => s.WakeUpType, deviceDtoNew.WakeUpType)

                .Set(s=>s.IsNeedReset,deviceDtoNew.IsNeedReset)
                .Set(s => s.LoginTimes, deviceDtoNew.LoginTimes)
                .Set(s => s.OnLineTime, deviceDtoNew.OnLineTime)
                .Set(s => s.OnLineTimeString, deviceDtoNew.OnLineTimeString)
                .Set(s => s.OffLineTime, deviceDtoNew.OffLineTime)
                .Set(s => s.OffLineTimeString, deviceDtoNew.OffLineTimeString)
                .Set(s => s.LastDataTime, deviceDtoNew.LastDataTime)
                .Set(s => s.LastLoginTime, deviceDtoNew.LastLoginTime)
                .Set(s => s.ModifyTime, deviceDtoNew.ModifyTime)

                .Set(s => s.GpsValidDataCount, deviceDtoNew.GpsValidDataCount)
                .Set(s => s.GpsInValidDataCount, deviceDtoNew.GpsInValidDataCount)
                .Set(s => s.LbsValidDataCount, deviceDtoNew.LbsValidDataCount)
                .Set(s => s.LbsInValidDataCount, deviceDtoNew.LbsInValidDataCount)
                .Set(s => s.FristLoginTime, deviceDtoNew.FristLoginTime)
                
                .Set(s=>s.FristResetTotal ,deviceDtoNew.FristResetTotal)
                .Set(s=>s.LastResetCount,deviceDtoNew.LastResetCount)

                .Set(s=>s.ICCID,deviceDtoNew.ICCID)
                ; 

            var ret = mongoDBCommand.UpdateDocumentAsync(s => s.IMEI == deviceDtoNew.IMEI, update).GetAwaiter().GetResult();
            redisService.AddAsync(GeneralContainer.RedisNameSpaceIMEIDevice + deviceDtoNew.IMEI, deviceDtoNew);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="deviceDto">new</param>
        /// <param name="dto">old</param>
        private void ReLogin(DeviceDto deviceDto, DeviceDto dto)
        {
            deviceDto.LoginTimes = dto.LoginTimes + 1;
            deviceDto.OnLineTime = (long)(dto.OnLineTime + (dto.LastDataTime - dto.LastLoginTime).TotalSeconds);
            deviceDto.OffLineTime = (long)((BCGPSCommon.MongoDBDateTime.GetNowUtc() - dto.FristLoginTime).TotalSeconds - deviceDto.OnLineTime);
            deviceDto.OnLineTimeString = GetOnOffLineTimeStr(deviceDto.OnLineTime);
            deviceDto.OffLineTimeString = GetOnOffLineTimeStr(deviceDto.OffLineTime);
            deviceDto.LastDataTime = BCGPSCommon.MongoDBDateTime.GetNowUtc();
            deviceDto.LastLoginTime = BCGPSCommon.MongoDBDateTime.GetNowUtc();
            deviceDto.ModifyTime = BCGPSCommon.MongoDBDateTime.GetNowUtc();

            deviceDto.GpsValidDataCount = dto.GpsValidDataCount;
            deviceDto.GpsInValidDataCount = dto.GpsInValidDataCount;
            deviceDto.LbsValidDataCount = dto.LbsValidDataCount;
            deviceDto.LbsInValidDataCount = dto.LbsInValidDataCount;
            deviceDto.ResetCountTime = dto.ResetCountTime;
            deviceDto.ResetCountTimes = dto.ResetCountTimes;
            deviceDto.IsNeedReset = dto.IsNeedReset;

            deviceDto.LastResetCount = deviceDto.ResetTotal - dto.FristResetTotal;

            var update = Builders<DeviceDto>.Update
                .Set(s => s.HardwareVersion, deviceDto.HardwareVersion)
                .Set(s => s.HardwareCode, deviceDto.HardwareCode)
                .Set(s => s.FirmwareVersion, deviceDto.FirmwareVersion)
                .Set(s => s.FirmwareCode, deviceDto.FirmwareCode)
                .Set(s => s.deviceType, deviceDto.deviceType)
                .Set(s => s.ResetCount, deviceDto.ResetCount)
                .Set(s => s.ResetTotal,deviceDto.ResetTotal)
                .Set(s => s.TimeSpan, deviceDto.TimeSpan)
                .Set(s => s.SleepTime, deviceDto.SleepTime)
                .Set(s => s.SleepTimeOnErr, deviceDto.SleepTimeOnErr)
                .Set(s => s.SendTimes, deviceDto.SendTimes)
                .Set(s => s.BatteryVoltage, deviceDto.BatteryVoltage)
                .Set(s => s.WakeUpType, deviceDto.WakeUpType)

                .Set(s => s.LoginTimes, deviceDto.LoginTimes)
                .Set(s => s.OnLineTime, deviceDto.OnLineTime)
                .Set(s => s.OnLineTimeString, deviceDto.OnLineTimeString)
                .Set(s => s.OffLineTime, deviceDto.OffLineTime)
                .Set(s => s.OffLineTimeString, deviceDto.OffLineTimeString)
                .Set(s => s.LastDataTime, deviceDto.LastDataTime)
                .Set(s => s.LastLoginTime, deviceDto.LastLoginTime)
                .Set(s => s.ModifyTime, deviceDto.ModifyTime)

                .Set(s=>s.LastResetCount,deviceDto.LastResetCount)

                .Set(s => s.ICCID, deviceDto.ICCID)
                ;
            var ret = mongoDBCommand.UpdateDocumentAsync(s => s.IMEI == deviceDto.IMEI, update).GetAwaiter().GetResult();

            redisService.AddAsync(GeneralContainer.RedisNameSpaceIMEIDevice + deviceDto.IMEI, deviceDto);
        }
        #endregion 

        #region 更新最后数据时间
        public void UpdateLastDataTime(string imei, DateTime lastDataServerTime)
        {
            var update = Builders<DeviceDto>.Update
                .Set(s => s.ModifyTime, BCGPSCommon.MongoDBDateTime.GetNowUtc())
                .Set(s => s.LastDataTime, BCGPSCommon.MongoDBDateTime.GetUtc(lastDataServerTime));
            var ret = mongoDBCommand.UpdateDocumentAsync(s => s.IMEI == imei, update).GetAwaiter().GetResult();
            redisService.AddAsync(GeneralContainer.RedisNameSpaceIMEIDevice + imei, ret).GetAwaiter().GetResult();

        }
        #endregion

        #region 更新有效定位数统计
        public void UpdateGpsDataValidCount(string imei, bool isValid,string LocationType)
        { 
            DeviceDto dto;
            dto = redisService.Get<DeviceDto>(GeneralContainer.RedisNameSpaceIMEIDevice + imei); 
            if (dto == null)
                dto = mongoDBCommand.SelectDocumentAsync(s => s.IMEI == imei).GetAwaiter().GetResult();
            if (dto != null)
            { 
                if (isValid)
                {
                    if (LocationType == "GPS+北斗")
                    {
                        dto.GpsValidDataCount = dto.GpsValidDataCount + 1;
                        var update = Builders<DeviceDto>.Update
                            .Set(s => s.GpsValidDataCount, dto.GpsValidDataCount);
                        var ret = mongoDBCommand.UpdateDocumentAsync(s => s.IMEI == imei, update).GetAwaiter().GetResult();
                    }
                    else if (LocationType == "LBS")
                    {
                        dto.LbsValidDataCount = dto.LbsValidDataCount + 1;
                        var update = Builders<DeviceDto>.Update
                            .Set(s => s.LbsValidDataCount, dto.LbsValidDataCount);
                        var ret = mongoDBCommand.UpdateDocumentAsync(s => s.IMEI == imei, update).GetAwaiter().GetResult();
                    }
                }
                else
                {
                    if (LocationType == "GPS+北斗")
                    {
                        dto.GpsInValidDataCount = dto.GpsInValidDataCount + 1;
                        var update = Builders<DeviceDto>.Update
                            .Set(s => s.GpsInValidDataCount, dto.GpsInValidDataCount);
                        var ret = mongoDBCommand.UpdateDocumentAsync(s => s.IMEI == imei, update).GetAwaiter().GetResult();
                    }
                    else if (LocationType == "LBS")
                    {
                        dto.LbsInValidDataCount = dto.LbsInValidDataCount + 1;
                        var update = Builders<DeviceDto>.Update
                            .Set(s => s.LbsInValidDataCount, dto.LbsInValidDataCount);
                        var ret = mongoDBCommand.UpdateDocumentAsync(s => s.IMEI == imei, update).GetAwaiter().GetResult();
                    }

                }
                redisService.AddAsync(GeneralContainer.RedisNameSpaceIMEIDevice + imei, dto); 
            }
            else
            {
                Msg.WirteLine("error : " +imei , 10);
            }
        }
        #endregion

        #region 在线时间转中文
        private string GetOnOffLineTimeStr(long totalSeconds)
        {
            if (totalSeconds > 0)
            {
                TimeSpan span = new TimeSpan(0, 0, (int)totalSeconds);

                long days = span.Days;


                long hours = span.Hours;


                long minutes = span.Minutes;

                long seconds = span.Seconds;

                if (days > 0)
                    return $"{days}天{hours}小时{minutes}分{seconds}秒";
                if (hours > 0)
                    return $"{hours}小时{minutes}分{seconds}秒";
                if (minutes > 0)
                    return $"{minutes}分{seconds}秒";
                if (seconds > 0)
                    return $"{seconds}秒";
                return "0秒";
            }
            else
                return "0秒";
        }

        #endregion



        #region 接口AIP用

        public DeviceDto Get(string imei)
        {
            DeviceDto dto = redisService.Get<DeviceDto>(GeneralContainer.RedisNameSpaceIMEIDevice + imei);
            if (dto != null)
                return dto;
            else
            {
                dto = mongoDBCommand.SelectDocumentAsync(s => s.IMEI == imei).GetAwaiter().GetResult();
                if (dto != null)
                    return dto;
                else
                    return new DeviceDto()
                    {
                        IMEI = imei,
                        HardwareCode = "NotLogin",
                    };
            }
        }
        public PageableList<DeviceDto> GetList(string imei, bool desc, int index, int size)
        {
            index = index > 0 ? index - 1 : 0;
            if (!string.IsNullOrWhiteSpace(imei))
            {
                var a = Get(imei);
                var b = new List<DeviceDto>();
                if (a != null)
                    b.Add(a);
                return new PageableList<DeviceDto>()
                {
                    Count = 1,
                    ServerTime = DateTime.Now,
                    Items = b,
                };
            }
            else
            {
                return mongoDBCommand.SelectDocumentsAsync(s => s.IMEI != "", s =>s.LastDataTime, desc, index * size, size).GetAwaiter().GetResult();
            }
        }

        public DeviceDto ResetCount(string imei)
        { 
            var dto = mongoDBCommand.SelectDocumentAsync(s => s.IMEI == imei).GetAwaiter().GetResult();
            if (dto == null)
                throw new ArgumentException("IMEI不存在!");

            var update = Builders<DeviceDto>.Update
                .Set(s => s.ResetCountTimes, dto.ResetCountTimes + 1)
                .Set(s => s.ResetCountTime, BCGPSCommon.MongoDBDateTime.GetNowUtc()) 
                .Set(s => s.IsNeedReset, true);
            dto = mongoDBCommand.UpdateDocumentAsync(s => s.IMEI == imei, update).GetAwaiter().GetResult();

            var newDto = mongoDBCommand.SelectDocumentAsync(s => s.IMEI == imei).GetAwaiter().GetResult();
            if (newDto == null)
                throw new ArgumentException("出现错误,请重试!");
            else
                redisService.AddAsync(GeneralContainer.RedisNameSpaceIMEIDevice + imei, newDto);
            return newDto;
        }
        #endregion


    }
}